﻿@page "/"
@inject NavigationManager navigationManager
@using Microsoft.AspNetCore.SignalR.Client
@using System.ComponentModel.DataAnnotations
@inject Blazored.LocalStorage.ILocalStorageService localStorage
@inject IJSRuntime JS
@using Microsoft.JSInterop
@using IndexedDB.Blazor

@if (!_isChatting)
{
    <p>
        输入您的名字开始聊天:
    </p>

    <input type="text" maxlength="32" @bind="@_username" />
    <button type="button" @onclick="@Chat"><span class="oi oi-chat" aria-hidden="true"></span> 开始畅聊!</button>

    // Error messages
    @if (_message != null)
    {
        <div class="invalid-feedback">@_message</div>
        <small id="emailHelp" class="form-text text-muted">@_message</small>
    }
}
else
{
    // banner to show current user
    <div class="alert alert-secondary mt-4" role="alert">
        <span class="oi oi-person mr-2" aria-hidden="true"></span>
        <span>欢迎<b>@_username</b>加入聊天室</span>
        <button class="btn btn-sm btn-warning ml-md-auto" @onclick="@DisconnectAsync">断开连接</button>
    </div>

     @*display messages*@
    <div id ="scrollbox">
        @foreach (var item in _messages)
        {
            @if (item.IsNotice)
            {
                <div class="alert alert-info">@item.Body</div>
            }
            else
            {
                <div class="@item.CSS">
                    <div class="user">@item.Username</div>
                    <div class="msg">@item.Body</div>
                </div>
            }
        }
        <hr />
        <textarea class="input-lg" placeholder="enter your comment" @bind="@_newMessage"></textarea>
        <button class="btn btn-default" @onclick="@(() => SendAsync(_newMessage))">Send</button>
    </div>
}


@code {
    // flag to indicate chat status
    private bool _isChatting = false;

    // name of the user who will be chatting
    private string _username;

    // on-screen message
    private string _message;

    // new message input
    private string _newMessage;

    // list of messages in chat
    private List<Message> _messages = new List<Message>();

    private string _hubUrl;
    private HubConnection _hubConnection;

    ExampleDb db; 

    static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();



    protected override async Task  OnInitializedAsync()
    {
        _username = await localStorage.GetItemAsStringAsync("chat_username");
        await JS.InvokeVoidAsync("createChatTable");
        if (_username != null) {
            _isChatting = true;
            Message[] result = await  JS.InvokeAsync<Message[]>("ReadData");
            Console.WriteLine(result.Length);
            _messages = result.ToList<Message>();
            await Chat();
        }
    }

    public async Task Chat()
    {
        // check username is valid
        if (string.IsNullOrWhiteSpace(_username))
        {
            _message = "请输入一个名字";
            return;
        };

        var name = await localStorage.GetItemAsStringAsync("chat_username");
        Console.WriteLine("chat_username" + name);
        if (name == null) {
            await localStorage.SetItemAsStringAsync("chat_username", _username);
        }
        try
        {
            // Start chatting and force refresh UI.
            _isChatting = true;
            await Task.Delay(1);

            // Create the chat client
            string baseUrl = navigationManager.BaseUri;


            _hubConnection = new HubConnectionBuilder()
                .WithUrl(navigationManager.ToAbsoluteUri("/chathub"))
                .Build();

            _hubConnection.On<string, string>("ReceiveMessage", BroadcastMessage);

            await _hubConnection.StartAsync();

            await SendAsync($"[Notice] {_username} 加入聊天室.");
        }
        catch (Exception e)
        {
            _message = $"ERROR: Failed to start chat client: {e.Message}";
            _isChatting = false;
        }
    }

    private async void BroadcastMessage(string name, string message)
    {
        //_username 每次打开一个网页都会是新的。有先后顺序
        bool isMine = name.Equals(_username, StringComparison.OrdinalIgnoreCase);
        var new_message = new Message(name, message, isMine);
        _messages.Add(new_message);
        // Inform blazor the UI needs updating
        StateHasChanged();
        await JS.InvokeVoidAsync("InsertValue", new_message);
    }

    private async Task DisconnectAsync()
    {
        if (_isChatting)
        {
            await SendAsync($"[Notice] {_username} left chat room.");

            await _hubConnection.StopAsync();
            await _hubConnection.DisposeAsync();

            _hubConnection = null;
            await localStorage.RemoveItemAsync("chat_username");
            _isChatting = false;
        }
    }

    private async Task SendAsync(string message)
    {
        if (_isChatting && !string.IsNullOrWhiteSpace(message))
        {
            await _hubConnection.SendAsync("SendMessage", _username, message);
            _newMessage = string.Empty;
        }
    }

    public class Message
    {       
        public  Message() {

        }

        public Message(string username, string body, bool mine)
        {
            Username = username;
            Body = body;
            Mine = mine;
        }
        public string Username { get; set; }
        public string Body { get; set; }
        public bool Mine { get; set; }
        // public bool IsNotice { get =>  Body.StartsWith("[Notice]"); public set => IsNotice = value; }

        public bool IsNotice
        {
            get { return Body.StartsWith("[Notice]"); } 
            set {}
        }
        public string CSS {
            get { return Mine ? "sent" : "received"; }
            set {}
        }

        public int Id { get; set; }
    }

    
    public class Person
    {
        public long Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class ExampleDb : IndexedDb
    {
        public ExampleDb(IJSRuntime jSRuntime, string name, int version) : base(jSRuntime, name, version) { }
        public IndexedSet<Message> Message { get; set; }
    }

}